package com.datamigration;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;

import com.bss.GenericDAO;
import com.bss.model.Admission;
import com.bss.model.Attendent;
import com.bss.model.Bed;
import com.bss.model.Building;
import com.bss.model.Country;
import com.bss.model.CurrentAttendent;
import com.bss.model.IdCardType;
import com.bss.model.MedicalProblem;
import com.bss.model.Patient;
import com.bss.model.PaymentType;
import com.bss.model.Place;
import com.bss.model.Profession;
import com.bss.model.Relationship;
import com.bss.model.Religion;
import com.bss.model.Room;
import com.bss.model.State;

public class JPADemo {
	private EntityManager bssNewEntityManager;
	GenericDAO<Patient> patientDao;

	GenericDAO<Admission> admissionDao;
	private GenericDAO<Attendent> attendentDao;
	private GenericDAO<CurrentAttendent> currentAttendentDao;
	private GenericDAO<Country> countryDao;
	private GenericDAO<State> stateDao;
	private GenericDAO<Place> placeDao;
	private GenericDAO<Religion> religionDao;
	private GenericDAO<Profession> professionDao;
	private GenericDAO<MedicalProblem> medicalProblemDao;
	private GenericDAO<Building> buildingDao;
	private GenericDAO<IdCardType> idCardTypeDao;
	private GenericDAO<Relationship> relationshipDao;
	private GenericDAO<PaymentType> paymentTypeDao;
	private GenericDAO<Room> roomDao;

	public JPADemo() {
		EntityManagerFactory emf = Persistence.createEntityManagerFactory("bssPU");
		this.bssNewEntityManager = emf.createEntityManager();

		this.patientDao = new GenericDAO<Patient>(Patient.class);
		this.patientDao.setEm(this.bssNewEntityManager);
		this.admissionDao = new GenericDAO<Admission>(Admission.class);
		this.admissionDao.setEm(this.bssNewEntityManager);

		this.attendentDao = new GenericDAO<Attendent>(Attendent.class);
		this.attendentDao.setEm(this.bssNewEntityManager);
		this.currentAttendentDao = new GenericDAO<CurrentAttendent>(CurrentAttendent.class);
		this.currentAttendentDao.setEm(this.bssNewEntityManager);

		this.countryDao = new GenericDAO<Country>(Country.class);
		this.countryDao.setEm(this.bssNewEntityManager);
		this.stateDao = new GenericDAO<State>(State.class);
		this.stateDao.setEm(this.bssNewEntityManager);
		this.placeDao = new GenericDAO<Place>(Place.class);
		this.placeDao.setEm(this.bssNewEntityManager);
		this.religionDao = new GenericDAO<Religion>(Religion.class);
		this.religionDao.setEm(this.bssNewEntityManager);

		this.professionDao = new GenericDAO<Profession>(Profession.class);
		this.professionDao.setEm(this.bssNewEntityManager);

		this.medicalProblemDao = new GenericDAO<MedicalProblem>(MedicalProblem.class);
		this.medicalProblemDao.setEm(this.bssNewEntityManager);
		this.buildingDao = new GenericDAO<Building>(Building.class);
		this.buildingDao.setEm(this.bssNewEntityManager);
		this.idCardTypeDao = new GenericDAO<IdCardType>(IdCardType.class);
		this.idCardTypeDao.setEm(this.bssNewEntityManager);
		this.relationshipDao = new GenericDAO<Relationship>(Relationship.class);
		this.relationshipDao.setEm(this.bssNewEntityManager);
		this.paymentTypeDao = new GenericDAO<PaymentType>(PaymentType.class);
		this.paymentTypeDao.setEm(this.bssNewEntityManager);
		this.roomDao = new GenericDAO<Room>(Room.class);
		this.roomDao.setEm(this.bssNewEntityManager);

	}

	public EntityManager getEntityManager() {
		return this.bssNewEntityManager;
	}

	public static void main(String[] args) {
		JPADemo demo = new JPADemo();

		long time1 = System.nanoTime();

		demo.getEntityManager().getTransaction().begin();
		// String ql =
		// "Select p from com.bss.model.Patient p where p.id in ( Select distinct a.patient.id from com.bss.model.Admission a where a.dateOfAdmission > '2009-01-01' )";

		// String ql =
		// "Select b from com.bss.model.Bed b where b.id not in (Select bb.bed.id from com.bss.model.BedBooking bb where bb.checkOutDate is null)";
		// String ql =
		// "Select bb from com.bss.model.BedBooking bb where bb.checkOutDate is null";

		// demo.demoRoomOccupancy();
		demo.demoCurrentAdmissions();

		demo.getEntityManager().getTransaction().commit();

		long time2 = System.nanoTime();

		System.out.println("time taken " + ((time2 - time1) / 1000000000.0));
	}

	void demoCurrentAdmissions() {

		String ql = "Select p.firstName from com.bss.model.Patient p where p.firstName like 'Su%' and p.id not in (Select a.patient.id from com.bss.model.Admission a where a.dateOfExit is null) ";

		Query q = this.getEntityManager().createQuery(ql);

		// List<Admission> buildings = q.getResultList();
		//
		// for (Admission o : buildings) {
		//
		// System.out.println(o.getId());
		// }

		for (Object i : q.getResultList()) {
			System.out.println(i);
		}
	}

	void demoRoomOccupancy() {

		String ql = "Select b from com.bss.model.Building b";

		Query q = this.getEntityManager().createQuery(ql);

		List<Building> buildings = q.getResultList();

		for (Building o : buildings) {

			if (o instanceof Building) {
				System.out.println((o).getName());
				(o).getRooms().size();
				Building b = o;

				for (Room r : b.getRooms()) {
					System.out.println("\t\t" + r.getRoomNumber());
				}

			}
		}

		List<Integer> occupiedRoomKeys;

		List<Integer> occupiedBedKeys;

		Query q1 = this.getEntityManager().createQuery(
				"Select r from Room r join r.roomBookings as rb where rb.checkOutDate is null");

		occupiedRoomKeys = new ArrayList<Integer>();
		for (Room room : (List<Room>) q1.getResultList()) {
			System.out.println("Occupied room: " + room.getRoomNumber());
			occupiedRoomKeys.add(room.getId());
		}

		Query q2 = this.getEntityManager()
				.createQuery("Select b from Bed b join b.bedBookings as bb where bb.checkOutDate is null");

		occupiedBedKeys = new ArrayList<Integer>();

		for (Bed bed : (List<Bed>) q2.getResultList()) {
			System.out.println("Occupied bed: " + bed.getBedNumber());
			occupiedBedKeys.add(bed.getId());
		}

		this.populateOccupancy(buildings, occupiedRoomKeys, occupiedBedKeys);

	}

	public void populateOccupancy(final List<Building> buildings, List<Integer> occupiedRoomKeys, List<Integer> occupiedBedKeys) {
		for (Building building : buildings) {
			for (Room room : building.getRooms()) {

				room.setProposedRate(room.getRate());
				room.setOccupied(false);
				room.setSelected(false);
				if (!room.isDormitory()) {

					if ((occupiedRoomKeys != null) && occupiedRoomKeys.contains(room.getId())) {
						room.setOccupied(true);
					}
				} else {
					for (Bed bed : room.getBeds()) {

						bed.setSelected(false);
						// Dormitory bed rate is same is Room rate
						bed.setProposedRate(room.getRate());
						bed.setOccupied(false);

						if ((occupiedBedKeys != null) && occupiedBedKeys.contains(bed.getId())) {
							bed.setOccupied(true);
						}
					}
				}
			}
		}
	}
}
